#ifndef BLINK_H
#define BLINK_H

#include <QDebug>
#include <QThread>
#include <QEventLoop>
#include "object.h"
#include "cv.h"
#include "highgui.h"

class BlinkDetector;

/**

ISSUES FOUND:

FIXED 1) The number of connected components for a valid eye pair is set to be 2, which
is often not the case for my cheap webcams(there are often more than two contours in the
difference image).
2) Due to the instrinsic problem of the cameras, that if the capturing is slow, blurring effects
break the liveness between two frames if object is moving fast. This might be minimised
using fast fire-wire video cameras.
3) The subtracted eye contours is often distorted, we may need to approximate their shape to
predefined eye shape, so the template for tracking stage will achieve more accuracy.
4) Lighting condition really matters the goodness of eye blink detection


The template created at the detection frame may not be good to do tracking, as at that time the
pose of eye is not fully open.


**/

using namespace cv;

#define TPL_WIDTH 	50
#define TPL_HEIGHT 	30
#define WIN_WIDTH	TPL_WIDTH * 2
#define WIN_HEIGHT	TPL_HEIGHT * 2
#define TPL_HOFF        -TPL_WIDTH / 2
#define TPL_VOFF        -TPL_HEIGHT / 2 + 5

#define TM_THRESHOLD	0.90
#define STAGE_INIT	1
#define STAGE_TRACKING	2

#define MAX_COMP_WDIFF	30
#define MAX_COMP_HDIFF	20
#define MAX_COMP_VDIFF	30
#define MIN_COMP_WIDTH  5
#define MIN_COMP_HEIGHT 4
#define MAX_COMP_WIDTH  40
#define MAX_COMP_HEIGHT 30
#define MIN_COMP_HRATIO 1
#define MAX_COMP_HRATIO 15
#define MIN_EYE_BASELINE 30
#define MAX_EYE_BASELINE 150

#define OPEN_ITERATIONS 2

#define SHOW_DIFF       0
#define MAX_CLUSTERS    2// only support 2 atm
#define MAX_POINTS      5000

#define POINT_TL(r)	cvPoint(r.x, r.y)
#define POINT_BR(r)	cvPoint(r.x + r.width, r.y + r.height)
#define POINTS(r)	POINT_TL(r), POINT_BR(r)


#define DRAW_RECTS(f, d, rw, ro)					\
    do {								\
    cvRectangle(f, POINTS(rw), CV_RGB(255, 0, 0), 1, 8, 0);		\
    cvRectangle(f, POINTS(ro), CV_RGB(0, 255, 0), 1, 8, 0);		\
    cvRectangle(d, POINTS(rw), cvScalarAll(255),  1, 8, 0);		\
    cvRectangle(d, POINTS(ro), cvScalarAll(255),  1, 8, 0);		\
    } while(0)

#define	DRAW_TEXT(f, t, d, use_bg)				        \
    if (d)								\
{									\
    CvSize _size;							\
    cvGetTextSize(t, &font, &_size, NULL);				\
    if (use_bg)								\
{									\
    cvRectangle(f, cvPoint(0, f->height), 				\
    cvPoint(_size.width + 5, 					        \
    f->height - _size.height * 2),		                        \
    CV_RGB(255, 0, 0), CV_FILLED, 8, 0);		                \
}									\
    cvPutText(f, t, cvPoint(2, f->height - _size.height / 2),	        \
    &font, CV_RGB(255,255,0));						\
    d--;								\
}

class BlinkDetector : public QThread
{
    Q_OBJECT
public:
    BlinkDetector( CvCapture *, QObject *parent = 0 );
    ~BlinkDetector();
    void run();
signals:
    // ( x, y ) is the position for the left eye
    // w is the distance between two eyes
    // use this signal to transfer eye tracking result
    void povChanged( int x, int y, int w );
    void povChanged( Point2f leye, Point2f reye );
    void imageChanged( IplImage *, IplImage * );
private:
    int  get_eye_pairs( IplImage* img, IplImage* prev, CvRect* eye, CvRect* eye2 );
    int  is_eye_pair2( CvMat *ptsa, CvMat *ptsb, CvRect* eye, CvRect* eye2 ); // k-means implementation
    int  locate_eye( IplImage* img, IplImage* tpl, CvRect* window, CvRect* eye, int use_window = 1, float scale = 1 );
    int  locate_iris( IplImage* img, IplImage* tpl, CvRect* eye );
    void delay_frames( int nframes );
    void init();
    void exit_nicely( char* msg );
private:
    CvCapture*         capture;
    IplImage           * frame, * kmimg, * gray, * prev, * diff, * tpl, * tpl2, *iris;
    CvMemStorage*      storage;
    IplConvKernel*     kernel;
    CvFont	       font;
    CvScalar           color_tab[5];
    int                using_full_window;
    char* wnd_name;
    char* wnd_debug;
    MyGLObject *_obj;
    bool               _error;
    int _init_width;
    int _cam_id;
};
#endif // BLINK_H







